// 原型式继承（注意是原型式继承，不是原型链继承）
// 原理是创建一个构造函数，构造函数的原型指向对象，然后调用new操作符创建一个实例，最后返回这个实例。本质是一个浅拷贝
// （1）声明一个函数，传入一个对象
// （2）在该函数内部创建一个构造函数，将传入的对象指到构造函数的原型上
// （3）返回这个构造函数的实例

// 缺点：(1)对于引用类型的属性，可以在不同实例间共享，修改其中一个实例的引用类型属性，其他实例属性也会被修改
// (2) 若父类是构造函数时，无法像父类传参，也无法继承父类构造函数的属性

// 🌰
function createObj(obj){
    function F(){}
    F.prototype = obj;
    return new F();
}

var person = {
    name: 'yunxi',
    friends:['sun','wu']
}

var person1 = createObj(person);
console.log(person1); // {}
console.log(person1.name); // yunxi
console.log(person1.friends); // [ 'sun', 'wu' ]

// ES5通过Object.create()方法规范来原型式继承。
// 支持传2个参数
// 第一个参数：用作新对象原型的对象
// 第二个参数：（可选）一个伪新对象定义额外属性的对象

var man = {
    name: 'yunxi',
    friends: ['bailu','jinghao']
}

var man1 = Object.create(man);
console.log(man1); // {}
console.log(man1.name); // yunxi
console.log(man1.friends); // [ 'bailu', 'jinghao' ]

var man2 = Object.create(man,{
    age:{
        value:22
    },
    work:{
        value: 'super star'
    }
})

console.log(man2); // {}
console.log(man2.age); // 22
console.log(man2.work); // super star


// 🌰
function createObj2(obj){
    function Person(){} // 创建一个构造函数
    Person.prototype = obj; // 将对象指向这个构造函数的原型，这样构造函数的实例就可以调用原型的方法
    return new Person();
}

// 1 若父类是引用类型时
var person1_1 = {
    name:'chris',
    age:18,
    friends:['lili','lucy'],
    getName:function(){
        console.log('name is:'+this.name)
    }
}

var p = createObj2(person1_1);
var p2 = createObj2(person1_1);
console.log(p);  // {}
console.log(p.__proto__);  // { name: 'chris', age: 18, getName: [Function: getName] }
console.log(p.name);  // chris
console.log(p.age);  // 18
console.log(p2.name) // chris
p.getName();  // name is:chris
console.log(p.name === p2.name); // true
console.log(p.getName === p2.getName); // true
p.name = 'cheng';
console.log(p.name); // cheng
console.log(p2.name); // chris

p.getName = function(){
    console.log('我改写了getName');
}

p.getName(); // 我改写了getName
p2.getName(); // name is:chris

console.log(p.friends) // [ 'lili', 'lucy' ]
console.log(p2.friends) // [ 'lili', 'lucy' ]

p.friends.pop();

console.log(p.friends); // [ 'lili' ]
console.log(p2.friends); // [ 'lili' ]

// 2. 若父类是构造函数时

function Child(money){
    this.money = money;
    this.getMoney = function(){
        console.log('get child money')
    }
}

Child.prototype.doWork = function(){
    console.log('好好学习');
}

var child = createObj(Child);
console.log(child); // Function {}
console.log(child.money) // undefined
console.log(child.getMoney) // undefined
console.log(child.doWork) // undefined
